--[[
-- slt - Simple Lua Template
--
-- Project page: http://code.google.com/p/slt/
--
-- @License
-- MIT License
--
-- @Copyright
-- Copyright (C) 2011 henix.
--]]

--[[
-- Changelog
--
-- 2011-7-2 henix
-- 		Version 0.1
--]]
slt = {}

-- process included file
-- @return string
local function precompile(template, start_tag, end_tag)
	local result = {}
	local orig_stag = start_tag
	start_tag = start_tag..'include:'

	local start1, end1 = string.find(template, start_tag, 1, true)
	local start2 = nil
	local end2 = 0
	local fin = nil
	local filename = nil
	local func = nil
	local err

	while start1 ~= nil do
		if start1 > end2 + 1 then
			table.insert(result, string.sub(template, end2 + 1, start1 - 1))
		end
		start2, end2 = string.find(template, end_tag, end1 + 1, true)
		if start2 ~= nil then
			-- NOTE: file name in the template file must be a quoted string
			func, err = loadstring('return '..string.sub(template, end1 + 1, start2 - 1))
			if func == nil then
				return nil, err
			end
			filename = func()
			fin, err = io.open(filename)
			if fin == nil then
				return nil, err
			end
			-- Be careful! DO NOT include files recursively! I don't detect this.
			table.insert(result, precompile(fin:read('*a'), orig_stag, end_tag))
			fin:close()
			start1, end1 = string.find(template, start_tag, end2 + 1, true)
		else
			-- end tag not found
			end2 = end1
			start1 = nil
			-- we could error it, but we ignore it here
		end
	end
	table.insert(result, string.sub(template, end2 + 1))
	return table.concat(result)
end

-- @return function
function slt.loadstring(template, start_tag, end_tag, output_func)
	-- compile it to lua code
	local lua_code = {}
	if start_tag == nil then
		start_tag = '#{'
	end
	if end_tag == nil then
		end_tag = ' }'
	end
	if output_func == nil then
		output_func = "outputfn"
	end

	local err

	template, err = precompile(template, start_tag, end_tag)
	if template == nil then
		return nil, err
	end

	local start1, end1 = string.find(template, start_tag, 1, true)
	local start2 = nil
	local end2 = 0

	local cEqual = string.byte('=', 1)

	while start1 ~= nil do
		if start1 > end2 + 1 then
			table.insert(lua_code, output_func..'('..string.format("%q", string.sub(template, end2 + 1, start1 - 1))..')')
		end
		start2, end2 = string.find(template, end_tag, end1 + 1, true)
		if start2 ~= nil then
			if string.byte(template, end1 + 1) ~= cEqual then
				table.insert(lua_code, string.sub(template, end1 + 1, start2 - 1))
			else
				table.insert(lua_code, output_func..'('..string.sub(template, end1 + 2, start2 - 1)..')')
			end
			start1, end1 = string.find(template, start_tag, end2 + 1, true)
		else
			-- end tag not found
			end2 = end1
			start1 = nil
			-- we could error it, but we ignore it here
		end
	end
	table.insert(lua_code, output_func..'('..string.format("%q", string.sub(template, end2 + 1))..')')
	return loadstring(table.concat(lua_code, '\n'))
end

-- @return function
function slt.loadfile(filename, start_tag, end_tag, output_func)
	local fin = io.open(filename)
	local all = fin:read('*a')
	fin:close()
	return slt.loadstring(all, start_tag, end_tag, output_func)
end

function slt.render(f, env)
	if env == nil then
		env = _G
	end
	setfenv(f, env)()
end

return slt
